package com.service.business.member.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.service.business.base.controller.req.LoginReq;
import com.service.business.base.controller.req.PhoneRegisterReq;
import com.service.business.base.controller.req.RegisterReq;
import com.service.business.base.dto.LoginUserSession;
import com.service.business.base.enums.SmsTypeEnum;
import com.service.business.base.service.CoinService;
import com.service.business.base.service.CoinsPriceService;
import com.service.business.base.service.ConfigService;
import com.service.business.member.controller.rep.MemberInfoRep;
import com.service.business.member.controller.rep.MemberTeamPageRep;
import com.service.business.member.controller.rep.TotalMemberTeamRep;
import com.service.business.member.controller.req.*;
import com.service.business.member.enums.MemberEnums;
import com.service.business.member.service.*;
import com.service.business.order.service.OrderProductHrComboService;
import com.service.business.support.SessionUtil;
import com.service.business.support.VerifyCodeUtil;
import com.service.business.utils.ObjUtil;
import com.service.business.utils.PwdUtils;
import com.service.core.constant.BusinessStatus;
import com.service.core.exception.CommonException;
import com.service.core.rest.response.CommonPageRep;
import com.service.dao.constants.ConfigConstants;
import com.service.dao.enums.CommonStatusEnums;
import com.service.dao.enums.GradeEnum;
import com.service.dao.enums.HashRateOrderEnums;
import com.service.dao.enums.MemberJAType;
import com.service.dao.mapper.CoinsMapper;
import com.service.dao.mapper.MemberMapper;
import com.service.dao.mapper.MemberStoreMapper;
import com.service.dao.mapper.MemberVerifiedMapper;
import com.service.dao.model.*;
import com.service.dao.po.MemberCache;
import com.service.utility.common.RandomUtil;
import com.service.utility.common.TotpUtil;
import com.service.utility.modelmapper.ModelMapperUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <dl>
 * <dt>back-end</dt>
 * <dd>Description:</dd>
 * <dd>Copyright: Copyright (C) 2015</dd>
 * <dd>Company: </dd>
 * <dd>CreateDate: 2019年09月19日</dd>
 * </dl>
 *
 * @author
 */
@Slf4j
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService {

    @Autowired
    private SessionUtil sessionUtil;
    @Autowired
    private CoinService coinService;
    @Autowired
    private VerifyCodeUtil verifyCodeUtil;
    @Autowired
    private MemberStoreMapper memberStoreMapper;
    @Autowired
    private MemberCacheService memberCacheService;
    @Autowired
    private MemberGradeConfigService memberGradeConfigService;
    @Autowired
    private MemberVerifiedMapper memberVerifiedMapper;
    @Autowired
    private MemberPhoneInfoService memberPhoneInfoService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private MemberJAService memberJAService;
    @Autowired
    private OrderProductHrComboService orderProductHrComboService;
    @Autowired
    private MemberStarGradeConfigService starGradeConfigService;

    @Override
    public Member getMemberTop1(Integer memberId) {
        return baseMapper.getMemberTop1(memberId);
    }

    @Override
    public Member getMemberById(Integer memberId) {
        return baseMapper.getMemberById(memberId);
    }

    @Override
    public Member getMemberTop2(Integer memberId) {
        return baseMapper.getMemberTop2(memberId);
    }

    @Override
    public Member getMemberByAccount(String userAccount, MemberEnums.Status status) {
        return getOne(new QueryWrapper<Member>().lambda().eq(Member::getUserAccount, userAccount)
                .eq(Member::getUserStatus, status.getCode()));
    }

    private Member getMemberByAccountWithOutStatus(String userAccount){
        return getOne(new QueryWrapper<Member>().lambda().eq(Member::getUserAccount, userAccount));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberInfoRep doMemberEmailRegister(RegisterReq req) {
        Member newUser = buildRegisterMemberInfo(req);
        newUser.setEmail(req.getUserAccount());
        newUser.setUserName(newUser.getEmail());
        return saveMemberInfo4Register(newUser);
    }

    private Member buildRegisterMemberInfo(RegisterReq req) {
        verifyCodeUtil.verifyTextVerifyCode(req.getUserAccount(), req.getVerifyCode(), SmsTypeEnum.REGISTER);
        verifyCodeUtil.verifyImageVerifyCode(ConfigConstants.IMAGE_VERIFY_CODE, req.getPicCodeImage(), req.getPicVerifyCode());

        if(!ObjectUtils.isEmpty(getMemberByAccountWithOutStatus(req.getUserAccount()))){
            log.error("账号<{}>注册失败，登录账号已存在", req.getUserAccount());
            throw new CommonException("注册失败,登录账号已存在", "register_fail_mobile_exist");
        }

        Member recommendMember = null;
        if (!StringUtils.isEmpty(req.getInvitationCode())) {
            recommendMember = getOne(new QueryWrapper<Member>().lambda().eq(Member::getInvitationCode, req.getInvitationCode())
                    .eq(Member::getUserStatus, MemberEnums.Status.ACTIVE.getCode()));
            if (ObjectUtils.isEmpty(recommendMember)) {
                log.error("账号<{}>注册失败，推荐码<{}>不存在", req.getUserAccount(), req.getInvitationCode());
                throw new CommonException("注册失败，推荐码不存在", "register_fail_recommend_invalid");
            }
        }

        Member newUser = ModelMapperUtil.map(req, Member.class);
        newUser.setLoginSalt(RandomUtil.randomString(4));
        newUser.setSafetySalt(RandomUtil.randomString(4));
        newUser.setLoginPwd(PwdUtils.aesToMd5(newUser.getLoginPwd(), newUser.getLoginSalt()));

        PwdUtils.isValidSafetyPwd(newUser.getSafetyPwd());
        newUser.setSafetyPwd(PwdUtils.aesToMd5(newUser.getSafetyPwd(), newUser.getSafetySalt()));
        if (!ObjectUtils.isEmpty(recommendMember)) {
            newUser.setPid(recommendMember.getId());
            newUser.setGid(recommendMember.getPid());
            newUser.setGgid(recommendMember.getGid());
            newUser.setDeep(recommendMember.getDeep() + 1);
            String path = StringUtils.isBlank(recommendMember.getUserPath()) ?
                    "-" + recommendMember.getId() + "-" : recommendMember.getUserPath() + recommendMember.getId() + "-";
            newUser.setUserPath(path);
        }

        newUser.setActivate(MemberEnums.Status.ACTIVE.getCode());
        newUser.setUserStatus(MemberEnums.Status.ACTIVE.getCode());
        newUser.setRegIp(req.getRegIp());
        newUser.setCreateTime(new Date());
        newUser.setInvitationCode(RandomUtil.randomString(8).toUpperCase());
        return newUser;
    }

    private void buildMemberStore(Integer userId) {
        List<Coins> coinList = coinService.list(new LambdaQueryWrapper<Coins>()
                .eq(Coins::getCoinStatus, CommonStatusEnums.ACTIVE.getCode()));
//                .eq(Coins::getShowAsset, CommonStatusEnums.ACTIVE.getCode()));
        
        List<MemberStore> storeList = Lists.newLinkedList();
        Date current = new Date();
        coinList.forEach(x -> {
            MemberStore memberStore = new MemberStore();
            memberStore.setMemberId(userId);
            memberStore.setNum(BigDecimal.ZERO);
            memberStore.setFrostNum(BigDecimal.ZERO);
            memberStore.setCoinsId(x.getId());
            memberStore.setCoinsName(x.getCoinName());
            memberStore.setCreateTime(current);
            storeList.add(memberStore);
        });
        memberStoreMapper.insertBatch(storeList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberInfoRep doMemberPhoneRegister(PhoneRegisterReq req) {
        Member newUser = buildRegisterMemberInfo(req);
        newUser.setPhoneCode(req.getPhoneCode());
        newUser.setMobile(req.getUserAccount());
        newUser.setUserName(newUser.getMobile());
        return saveMemberInfo4Register(newUser);
    }

    private MemberInfoRep saveMemberInfo4Register(Member newUser) {
        int insertCount = baseMapper.insert(newUser);
        if (insertCount <= 0) {
            throw new CommonException("注册失败", "register_fail");
        }
        //初始化会员账户资金信息到redis中
        memberCacheService.initMemberCache4Register(newUser.getId(), newUser.getUserAccount());
        buildMemberStore(newUser.getId());
        return ModelMapperUtil.getStrictModelMapper().map(newUser, MemberInfoRep.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberInfoRep doLoginMember(LoginReq loginReq) {
        //verifyCodeUtil.verifyTextVerifyCode(loginReq.getUserAccount(), loginReq.getVerifyCode(), SmsTypeEnum.LOGIN);

        Member memberInfo = getMemberByAccount(loginReq.getUserAccount(), MemberEnums.Status.ACTIVE);
        if (ObjectUtils.isEmpty(memberInfo)) {
            throw new CommonException("登陆失败，未查询到有效用户", "login_fail_not_have_user");
        }
        String pwd = loginReq.getLoginPwd();
        pwd = PwdUtils.aesToMd5(pwd, memberInfo.getLoginSalt());
        if (!StringUtils.equals(pwd, memberInfo.getLoginPwd())) {
            throw new CommonException("登陆失败，密码不正确", "login_fail_pwd_invalid");
        }

        if (StringUtils.isNotEmpty(loginReq.getPhoneId())) {
            memberInfo.setPhoneId(loginReq.getPhoneId());
//            log.info("开始读取手机设备信息,{}",loginReq.getPhoneInfo());
            if (!ObjUtil.allFieldIsNULL(loginReq.getPhoneInfo())) {
                MemberPhoneInfo phoneInfo = ModelMapperUtil.getStrictModelMapper().map(loginReq.getPhoneInfo(), MemberPhoneInfo.class);
                memberPhoneInfoService.save(phoneInfo);
                memberInfo.setPhoneInfoId(phoneInfo.getId());
            }
            baseMapper.updateById(memberInfo);
        }
        LoginUserSession loginUserSession = ModelMapperUtil.getStrictModelMapper().map(memberInfo, LoginUserSession.class);
        loginUserSession.setSessionId(loginReq.getSessionId());
        loginUserSession.setUserId(memberInfo.getId());
        loginUserSession.setAccount(memberInfo.getUserAccount());
        loginUserSession.setStoreFreezeStatus(memberInfo.getStoreFreezeStatus());
        String token = sessionUtil.saveSession(loginUserSession);

        MemberInfoRep userInfoRep = ModelMapperUtil.getStrictModelMapper().map(memberInfo, MemberInfoRep.class);
        userInfoRep.setToken(token);

        //单机登录，记录当前登录人的token
        sessionUtil.savSessionId(memberInfo.getId(), userInfoRep.getToken());

        if (StringUtils.isNotBlank(memberInfo.getTotpSecret())) {
            userInfoRep.setFa(true);//需要谷歌两步验证
        } else {
            userInfoRep.setFa(false);
        }
        return userInfoRep;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberInfoRep getMemberInfoByToken() {
        LoginUserSession userSession = sessionUtil.getUser();
//        checkAndUpdateMemberGrade(userSession.getUserId());
//        checkAndUpdateMemberStarGrade(userSession.getUserId());
        MemberCache memberCache = memberCacheService.getMemberCache(userSession.getUserId());
        Integer memberVipGrade = memberGradeConfigService.checkMemberGrade(memberCache);
        memberCache.setMemberGrade(memberVipGrade);
        MemberGradeConfig memberGradeConfig = memberGradeConfigService.getById(memberVipGrade);
        if(!ObjectUtils.isEmpty(memberGradeConfig)){
            memberCache.setMemberGradeName(memberGradeConfig.getGradeName());
        }
        memberCacheService.setMemberCache(memberCache);
        Member member = getById(userSession.getUserId());
        if(!ObjectUtils.isEmpty(member)){
            MemberVerified memberVerified = memberVerifiedMapper.selectById(member.getId());
            if(!ObjectUtils.isEmpty(memberVerified)){
                member.setVerifyStatus(memberVerified.getVerifyStatus());
            }else{
                member.setVerifyStatus(0);
            }
            if(!ObjectUtils.isEmpty(memberGradeConfig)){
                member.setMemberGradeName(memberGradeConfig.getGradeName());
            }
        }
        return ModelMapperUtil.getStrictModelMapper().map(member, MemberInfoRep.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateMemberGrade(Integer memberId) {
        checkAndUpdateMemberGrade(memberCacheService.getMemberCache(memberId));
    }

    @Override
    public void checkAndUpdateMemberGrade(MemberCache memberCache) {
        Integer memberGrade = memberGradeConfigService.checkMemberGrade(memberCache);
        if (!ObjectUtils.nullSafeEquals(memberGrade, memberCache.getMemberGrade()) &&
                memberCache.getMemberGrade() < GradeEnum.eleven.getValue()) {
            memberCache.setMemberGrade(memberGrade);
            updateMemberGrade(memberCache.getMemberId(), memberGrade);
            memberCacheService.setMemberCache(memberCache);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateMemberStarGrade(Integer memberId) {
        checkAndUpdateMemberStarGrade(memberCacheService.getMemberCache(memberId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkAndUpdateMemberStarGrade(MemberCache memberCache) {
        Integer starGrade = starGradeConfigService.checkMemberStarGrade(memberCache);
        if (!ObjectUtils.nullSafeEquals(starGrade, memberCache.getStarGrade())) {
            memberCache.setStarGrade(starGrade);
            updateMemberStarGrade(memberCache.getMemberId(), starGrade);
            memberCacheService.setMemberCache(memberCache);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetMemberLoginPwd(ResetPassReq resetPassReq) {
        Member memberInfo = validForm(resetPassReq);

        Integer userId = memberInfo.getId();
        memberInfo = new Member();
        memberInfo.setId(userId);
        memberInfo.setLoginSalt(RandomUtil.randomString(4));
        memberInfo.setLoginPwd(PwdUtils.aesToMd5(resetPassReq.getPassword(), memberInfo.getLoginSalt()));
        baseMapper.updateById(memberInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetMemberSafetyPwd(ResetPassReq resetPassReq) {
        Member memberInfo = validForm(resetPassReq);
        Integer userId = memberInfo.getId();
        memberInfo = new Member();
        memberInfo.setId(userId);
        memberInfo.setSafetySalt(RandomUtil.randomString(4));
        memberInfo.setSafetyPwd(PwdUtils.aesToMd5(resetPassReq.getPassword(), memberInfo.getSafetySalt()));
        baseMapper.updateById(memberInfo);
    }

    private Member validForm(ResetPassReq resetPassReq) {
        Member memberInfo = validMemberByAccount(resetPassReq.getUserAccount());
        verifyCodeUtil.verifyTextVerifyCode(resetPassReq.getUserAccount(), resetPassReq.getVerifyCode(), SmsTypeEnum.RESET_PWD);
        verifyCodeUtil.verifyImageVerifyCode(ConfigConstants.IMAGE_VERIFY_CODE, resetPassReq.getPicCodeId(), resetPassReq.getPicCode());
        return memberInfo;
    }

    private Member validMemberByAccount(String account) {
        Member memberInfo = getMemberByAccount(account, MemberEnums.Status.ACTIVE);
        if (ObjectUtils.isEmpty(memberInfo)) {
            throw new CommonException("修改密码失败，账号不存在", "modify_pass_fail_user_invalid");
        }
        return memberInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyMemberLoginPwd(ModifyPwdReq modifyPwdReq) {
        Integer userId = sessionUtil.getUser().getUserId();
        Member memberInfo = baseMapper.selectById(userId);
        if (ObjectUtils.isEmpty(memberInfo)) {
            throw new CommonException("修改密码失败，账号不存在", "modify_pass_fail_user_invalid");
        }
        verifyCodeUtil.verifyTextVerifyCode(sessionUtil.getUser().getAccount(), modifyPwdReq.getVerifyCode(), SmsTypeEnum.RESET_PWD);

        memberInfo = new Member();
        memberInfo.setId(userId);
        memberInfo.setLoginSalt(RandomUtil.randomString(4));
        memberInfo.setLoginPwd(PwdUtils.aesToMd5(modifyPwdReq.getNewPass(), memberInfo.getLoginSalt()));
        baseMapper.updateById(memberInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void modifyMemberSafetyPwd(ModifyPwdReq modifyPwdReq) {
        Integer userId = sessionUtil.getUser().getUserId();
        Member memberInfo = baseMapper.selectById(userId);
        if (ObjectUtils.isEmpty(memberInfo)) {
            throw new CommonException("修改密码失败，账号不存在", "modify_pass_fail_user_invalid");
        }

        verifyCodeUtil.verifyTextVerifyCode(sessionUtil.getUser().getAccount(), modifyPwdReq.getVerifyCode(), SmsTypeEnum.RESET_PAY);
        PwdUtils.isValidSafetyPwd(modifyPwdReq.getNewPass());

        memberInfo = new Member();
        memberInfo.setId(userId);
        memberInfo.setSafetySalt(RandomUtil.randomString(4));
        memberInfo.setSafetyPwd(PwdUtils.aesToMd5(modifyPwdReq.getNewPass(), memberInfo.getSafetySalt()));
        baseMapper.updateById(memberInfo);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMemberInfo(MemberUpdateReq updateReq) {
        LoginUserSession userSession = sessionUtil.getUser();
        Integer userId = userSession.getUserId();
        Member member = ModelMapperUtil.getStrictModelMapper().map(updateReq, Member.class);
        member.setId(userId);

        baseMapper.updateById(member);
        if (StringUtils.isNotBlank(updateReq.getEmail())) {
            userSession.setEmail(updateReq.getEmail());
        }
        if (StringUtils.isNotBlank(updateReq.getUserName())) {
            userSession.setUsername(updateReq.getUserName());
        }
        if (StringUtils.isNotBlank(updateReq.getMobile())) {
            userSession.setMobile(updateReq.getMobile());
        }
        sessionUtil.saveSession(userSession);
    }


    @Override
    public boolean faStatus() {
        LoginUserSession userSession = sessionUtil.getUser();
        if (ObjectUtils.isEmpty(userSession)) {
            throw new CommonException("系统错误", "args_error");
        }
        Member memberInfo = baseMapper.selectById(userSession.getUserId());
        if (ObjectUtils.isEmpty(memberInfo)) {
            throw new CommonException("系统错误", "args_error");
        }
        //是否绑定2FA
        return !StringUtils.isEmpty(memberInfo.getTotpSecret());
    }

    @Override
    public TotalMemberTeamRep totalMemberTeam() {
        LoginUserSession userSession = sessionUtil.getUser();
        if (ObjectUtils.isEmpty(userSession)) {
            throw new CommonException("系统错误", "args_error");
        }
        TotalMemberTeamRep rep = new TotalMemberTeamRep();
        //获取当前用户的推荐用户
        List<Integer> recommendMemberIds = baseMapper.listByCurrentMemberPath(userSession.getUserId(),MemberEnums.Status.ACTIVE.getCode());
        if(ObjectUtils.isEmpty(recommendMemberIds)){
            rep.setPromotionSales(BigDecimal.ZERO);
            rep.setPromotionPeople(0);
            rep.setPromotionPerformance(BigDecimal.ZERO);
            rep.setTotalCommission(BigDecimal.ZERO);
            rep.setYesterdayCommission(BigDecimal.ZERO);
        }else{
            //推广销量
            BigDecimal promotionSales = orderProductHrComboService.totalEffectiveOrderPayByMemberList(recommendMemberIds,HashRateOrderEnums.getHrComboTotalStatus());
            rep.setPromotionSales(promotionSales);
            //推广人数
            rep.setPromotionPeople(recommendMemberIds.size());
            //推广业绩
            BigDecimal promotionPerformance = orderProductHrComboService.totalEffectiveOrderByMemberList(recommendMemberIds);
            rep.setPromotionPerformance(promotionPerformance);
            //累计佣金
            BigDecimal totalCommission = memberJAService.totalMemberStatement(userSession.getUserId(), MemberJAType.getTotalCommissionIncome(),null);
            rep.setTotalCommission(totalCommission);
            Date currentDate = new Date();
            Date yesterday = DateUtils.addDays(currentDate, -1);
            //昨日佣金
            BigDecimal yesterdayCommission = memberJAService.totalMemberStatement(userSession.getUserId(), MemberJAType.getTotalCommissionType(),yesterday);
            rep.setYesterdayCommission(yesterdayCommission);
        }

        return rep;
    }

    /**
     * @param gradeList
     * @Description: 获取用户等级处理列表中的用户集合
     * @Author: ty
     * @Date: 2021/5/6 16:12
     * @param: [grades]
     * @return: java.util.List<java.lang.Integer>
     */
    @Override
    public List<Member> getMemberIdsByGradeList(List<Integer> gradeList) {
        return list(new QueryWrapper<Member>().lambda()
            .in(Member::getVipGrade, gradeList)
        );
    }

    @Override
    public Map<String, Object> getTwoFa() {
        LoginUserSession userSession = sessionUtil.getUser();
        Map<String, Object> twoFa = new HashMap<>();
        if (ObjectUtils.isEmpty(userSession)) {
            throw new CommonException("系统错误", "args_error");
        }
        Member memberInfo = baseMapper.selectById(userSession.getUserId());
        if (StringUtils.isNotBlank(memberInfo.getTotpSecret())
                && StringUtils.equals(memberInfo.getTotpSecret(), userSession.getTotpSecret())) {
            //已经绑定
            twoFa.put("isbind", true);
        } else {
            String totpSecret = "";
            if (StringUtils.isEmpty(userSession.getTotpSecret())) {
                //没有绑定
                totpSecret = TotpUtil.generateSecretKey();
            } else {
                totpSecret = userSession.getTotpSecret();
            }
            SysConfig sysConfig = configService.getConfigByName(ConfigConstants.WEB_SITE_NAME);
            String totpQr = TotpUtil.getQRBarcodeURL(userSession.getAccount(), totpSecret, sysConfig.getConfValue());
            //更新session存放totp私钥
            userSession.setTotpSecret(totpSecret);
            sessionUtil.refreshSession(userSession);

            if (userSession.getAccount().contains("@")) {
                twoFa.put("type", "email");
            } else {
                twoFa.put("type", "phone");
            }
            twoFa.put("secret", totpSecret);
            twoFa.put("qr", totpQr);
            twoFa.put("isbind", false);
        }
        return twoFa;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindTwoFa(TwoFaReq twoFa) {
        LoginUserSession userSession = sessionUtil.getUser();
        if (StringUtils.isEmpty(userSession.getTotpSecret()) ||
                StringUtils.isEmpty(twoFa.getVerifyCode()) || twoFa.getFaCode() < 100000L) {
            throw new CommonException("系统错误", "args_error");
        }
        verifyCodeUtil.verifyTextVerifyCode(userSession.getAccount(), twoFa.getVerifyCode(), SmsTypeEnum.TWOFA);
        boolean isRight = TotpUtil.checkCode(userSession.getTotpSecret(), twoFa.getFaCode());
        if (!isRight) {
            userSession.setTotpSecret(null);
            sessionUtil.refreshSession(userSession);
            throw new CommonException("2FA验证码验证失败！", "two_fa_is_invalid");
        }
        Member member = new Member();
        member.setId(userSession.getUserId());
        member.setTotpSecret(userSession.getTotpSecret());
        baseMapper.updateById(member);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbindTwoFa(TwoFaReq twoFaReq) {
        if (twoFaReq.getFaCode() < 100000L) {
            throw new CommonException("解除绑定失败，参数异常", "args_error");
        }
        LoginUserSession userSession = sessionUtil.getUser();
        Member memberInfo = baseMapper.selectById(userSession.getUserId());
        if (ObjectUtils.isEmpty(memberInfo) || !memberInfo.getTotpSecret().equals(userSession.getTotpSecret())) {
            throw new CommonException("解除绑定失败，参数异常", "args_error");
        }
        boolean isRight = TotpUtil.checkCode(memberInfo.getTotpSecret(), twoFaReq.getFaCode());
        if (!isRight) {
            throw new CommonException("2FA验证失败！", "two_fa_is_invalid");
        }
        memberInfo.setTotpSecret(null);
        baseMapper.updateById(memberInfo);
        userSession.setTotpSecret(null);
        sessionUtil.refreshSession(userSession);
    }

    @Override
    public boolean checkTwoFa(TwoFaReq twoFa) {
        if (twoFa.getFaCode() <= 0) {
            throw new CommonException("两步验证码不能为空！", "two_fa_is_null");
        }
        LoginUserSession userSession = sessionUtil.getUser();
        if (StringUtils.isEmpty(userSession.getTotpSecret())) {
            throw new CommonException("系统错误", "args_error");
        }
        return TotpUtil.checkCode(userSession.getTotpSecret(), twoFa.getFaCode());
    }

    @Override
    public List<Member> selectByPidAndStatus(Integer memberId) {
        return list(new QueryWrapper<Member>().lambda().eq(Member::getPid, memberId)
                .eq(Member::getUserStatus, CommonStatusEnums.ACTIVE.getCode())
                .eq(Member::getActivate, CommonStatusEnums.ACTIVE.getCode()));
    }

    @Override
    public List<Member> selectByPathAndStatus(Integer memberId) {
        return list(new QueryWrapper<Member>().lambda()
                .like(Member::getUserPath, "-" + memberId + "-")
                .eq(Member::getUserStatus, CommonStatusEnums.ACTIVE.getCode())
                .eq(Member::getActivate, CommonStatusEnums.ACTIVE.getCode()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMemberGrade(Integer memberId, Integer grade) {
        Member member = new Member();
        member.setId(memberId);
        member.setVipGrade(grade);
        baseMapper.updateById(member);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateMemberStarGrade(Integer memberId, Integer grade) {
        baseMapper.updateById(Member.builder().id(memberId).starGrade(grade).build());
    }

    @Override
    public Integer countValidMemberByPath(Integer memberId, Integer grade){
        return baseMapper.countValidMemberByPath(memberId, grade);
    }

    @Override
    public Integer countMemberByPidAndStarGrade(Integer memberId, List<Integer> grade) {
        return baseMapper.countByParentIdAndStarGrade(memberId, grade);
    }

    @Override
    public void validSafetyPwd(Integer memberId, String safePwd) {
        Member loginMember = this.getById(memberId);
        if (StringUtils.isNotBlank(safePwd)) {
            String pwd = PwdUtils.aesToMd5(safePwd, loginMember.getSafetySalt());
            if (!StringUtils.equals(pwd, loginMember.getSafetyPwd())) {
                log.error("会员<{}>操作失败，支付密码错误", memberId);
                throw new CommonException(BusinessStatus.SAFETY_PWD_ERROR, "safety_pwd_by_error");
            }
        }
    }

    @Override
    public CommonPageRep<MemberTeamPageRep> pageMemberTeam(MemberTeamPageReq pageReq) {
        LoginUserSession userSession = sessionUtil.getUser();
        Page<Member> page = PageHelper.startPage(pageReq.getPageNo(), pageReq.getPageSize());
        LambdaQueryWrapper<Member> queryWrapper = new QueryWrapper<Member>().lambda()
                .eq(Member::getPid, userSession.getUserId())
                .eq(Member::getUserStatus, CommonStatusEnums.ACTIVE.getCode())
                .eq(Member::getActivate, CommonStatusEnums.ACTIVE.getCode());
        list(queryWrapper);

        List<MemberTeamPageRep> repList = page.getResult().stream().map(item -> {
            MemberTeamPageRep resultItem = new MemberTeamPageRep();
            resultItem.setMemberHeadImg(item.getImgHead());
            resultItem.setMemberName(item.getUserName());
            MemberCache memberCache = memberCacheService.getMemberCache(item.getId());
            resultItem.setConsume(memberCache.getTotalConsumption());
            resultItem.setPerformance(memberCache.getFilTeamReleaseNum());
            calculateChildrenTotal(item, resultItem);
            return resultItem;
        }).collect(Collectors.toList());

        return CommonPageRep.buildResultRep(page, repList);
    }

    private void calculateChildrenTotal(Member member, MemberTeamPageRep resultItem) {
        List<Member> children = selectByPathAndStatus(member.getId());
        AtomicReference<BigDecimal> totalPerformance = new AtomicReference<>(BigDecimal.ZERO);
        AtomicInteger experienceNum = new AtomicInteger(0);
        AtomicInteger directNum = new AtomicInteger(0);
        children.parallelStream().forEach(item -> {
            MemberCache memberCache = memberCacheService.getMemberCache(item.getId());
            totalPerformance.getAndAccumulate(memberCache.getTotalConsumption(), BigDecimal::add);
            if (ObjectUtils.nullSafeEquals(memberCache.getMemberGrade(), GradeEnum.two.getValue())
                    || ObjectUtils.nullSafeEquals(memberCache.getMemberGrade(), GradeEnum.twelve.getValue())) {
                experienceNum.getAndIncrement();
            }
            if (memberCache.getValidMember()) {
                directNum.getAndIncrement();
            }
        });

        resultItem.setDirectRecommendNum(directNum.get());
        resultItem.setExperienceNum(experienceNum.get());
        resultItem.setPerformance(totalPerformance.get());
    }

    @Override
    public boolean isDirectRelative(Member user, Member toUser) {

        if (isParent(user, toUser) || isParent(toUser, user)) {
            return true;
        }

        Set<String> userPathList = getPath2Set(user.getUserPath());
        if (ObjectUtils.isEmpty(userPathList)) {
            return false;
        }
        Set<String> tpUserPathList = getPath2Set(toUser.getUserPath());
        if (ObjectUtils.isEmpty(tpUserPathList)) {
            return false;
        }
        Sets.SetView<String> pathSet = Sets.intersection(userPathList, tpUserPathList);
        return pathSet.size() > 0;
    }

    private Set<String> getPath2Set(String path) {
        if (StringUtils.isBlank(path)) {
            return null;
        }
        return Arrays.stream(path.split("-"))
                .filter(StringUtils::isBlank).collect(Collectors.toSet());
    }

    private boolean isParent(Member user, Member toUser) {
        return ObjectUtils.nullSafeEquals(toUser.getPid(), user.getId())
                || ObjectUtils.nullSafeEquals(toUser.getGid(), user.getId())
                || ObjectUtils.nullSafeEquals(toUser.getGgid(), user.getId())
                || ObjectUtils.nullSafeEquals(user.getPid(), toUser.getId())
                || ObjectUtils.nullSafeEquals(user.getGid(), toUser.getId())
                || ObjectUtils.nullSafeEquals(user.getGgid(), toUser.getId());
    }

    @Override
    public List<Integer> getMemberPathList(String memberPath) {
        return Lists.newArrayList(memberPath.split("-"))
                .stream().filter(StringUtils::isNotBlank).map(Integer::parseInt).collect(Collectors.toList());
    }

    @Override
    public List<MemberInfoRep> listByUserAccount(String userAccount) {

        LoginUserSession session = sessionUtil.getUser();

        return list(new QueryWrapper<Member>().lambda()
                .like(Member::getUserAccount, userAccount)
                .eq(Member::getActivate, CommonStatusEnums.ACTIVE.getCode())
                .ne(Member::getUserAccount, session.getAccount())
                .eq(Member::getUserStatus, CommonStatusEnums.ACTIVE.getCode())).stream()
                .map(item -> ModelMapperUtil.map(item, MemberInfoRep.class)).collect(Collectors.toList());
    }
}


